package ms.unicorn.dsl.analysis.impl;

import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.emf.common.notify.Notification;

import ms.unicorn.Element;
import ms.unicorn.NotificationService;
import ms.unicorn.NotificationService.Subscription;
import ms.unicorn.dsl.analysis.AnalysisRegistryService.AnalysisRegistryListener;
import ms.unicorn.dsl.analysis.IAnalysis;
import ms.unicorn.dsl.analysis.IConversionCache;
import ms.unicorn.dsl.analysis.IConversionScheme;
import ms.unicorn.dsl.analysis.UnicornService;

public abstract class AbstractAnalysis implements IAnalysis, IConversionCache {
	
	private Map<String, Object> cache = new HashMap<String, Object>();
	private Map<Object, String> idCache = new HashMap<Object, String>();
	private Map<Object, Object> conversionData = new HashMap<Object, Object>();
	private Map<Object, WeakReference<Element>> map = new HashMap<Object, WeakReference<Element>>();
	private Element rootElement;
	
	public AbstractAnalysis(Element rootElement) {
		this.rootElement = rootElement;
	}
	
	protected <T> T convert() {
		IConversionScheme scheme = UnicornService.getConversionService().getConversionScheme(rootElement.getLanguage(), getConversionScheme());
		if (scheme != null)
			return scheme.convert(rootElement, this);
		return null;
	}
	
	@Override
	public String getText() {
		return String.format("%s on %s", getName(), rootElement!=null?rootElement.getName():"<null>");
	}
	
	public String getName() {
		return this.getClass().getSimpleName();
	}

	@Override
	public void runAnalysis() {
		UnicornService.getAnalysisRegistryService().notify(AnalysisRegistryListener.ANALYSIS_CHANGED, this);
	}

	@Override
	public void showAnalysisResult() {
		UnicornService.getAnalysisRegistryService().notify(AnalysisRegistryListener.ANALYSIS_ACTIVATED, this);
	}

	@Override
	public void hidedAnalysisResult() {
		UnicornService.getAnalysisRegistryService().notify(AnalysisRegistryListener.ANALYSIS_DEACTIVATED, this);
	}

	@Override
	public Object getConvertedObject(String objID) {
		return cache.get(objID);
	}

	@Override
	public Element getOriginalElement(Object convertedObject) {
		WeakReference<Element> ref = map.get(convertedObject);
		if (ref != null) {
			if (ref.get() != null)
				return ref.get();
			unmap(convertedObject);
		}
		return null;
	}

	@Override
	public void map(Element domainObject, Object obj) {
		cache.put(domainObject.getId(), obj);
		map.put(obj, new WeakReference<Element>(domainObject));
		idCache.put(obj, domainObject.getId());
	}

	@Override
	public void unmap(Object convertedObject) {
		map.remove(convertedObject);
		String id = idCache.get(convertedObject);
		if (id != null)
			cache.remove(id);
		idCache.remove(convertedObject);
	}
	
	@Override
	public void clearCache() {
		map.clear();
		idCache.clear();
		cache.clear();
		conversionData.clear();
	}

	@Override
	public Element getRootElement() {
		return this.rootElement;
	}
	
	@Override
	public String toString() {
		return getText();
	}
	

	@Override
	public boolean supportIncrementalChange() {
		return false;
	}

	@Override
	public Collection<Integer> getPreferChannels() {
		return null;
	}

	@Override
	public int hanldeSubscription(Object sender, int channel,
			Subscription<Notification, Object> subscription) {
		
		return NotificationService.SUBSCRIPTION_NORMAL;
	}

	public Map<Object, Object> getConversionData() {
		return conversionData;
	}

}
